namespace eval message {
    variable msgid 0
    variable headid 0

    variable options

    custom::defvar message_dest_list {} \
	[::msgcat::mc "List of message destination JIDs."] \
	-group Hidden

    custom::defgroup Messages [::msgcat::mc "Message and Headline options."] \
	-group Tkabbur

    disco::register_feature jabber:x:oob
}

proc message::process_message {connid from id type is_subject subject body err thread priority x} {
    switch -- $type {
	normal {
	    show_dialog $connid $from $type $subject $body $thread $priority $x
	    return stop
	}
    }
    return
}

hook::add process_message_hook \
    [namespace current]::message::process_message

proc message::show_dialog {connid from type subject body thread priority x {replyP 1}} {
    global font
    variable msgid

  if {$type == "normal"} {
       ::message_archive::log_message \
	    $from [jlib::connection_jid $connid] \
            $subject $body $x
       ::logger::log_message [chat::chatid $connid $from] $from normal $body $x
    }

    set mw .msgshow[incr msgid]
    toplevel $mw -class Message
    wm group $mw .

    if {$replyP} {
        set title [format [::msgcat::mc "Message from %s"] $from]
    } else {
        set title [format [::msgcat::mc "Extras from %s"] $from]
    }
    wm title $mw $title
    wm iconname $mw $title

    wm withdraw $mw

    frame $mw.bottom
    pack $mw.bottom -side bottom -fill x

    if {$replyP} {
        set bbox [ButtonBox $mw.bottom.buttons -spacing 10 -padx 10]
	$bbox add -text [::msgcat::mc "Reply"] \
	    -command [list message::send $mw -connection $connid]
        $bbox add -text [::msgcat::mc "Chat"] \
	    -command "chat::open_to_user $connid [list $from]
                      destroy $mw"
        $bbox add -text [::msgcat::mc "Close"] -command [list destroy $mw]
        bind $mw <Control-Return> "ButtonBox::invoke $bbox 0"
        bind $mw <Escape> "ButtonBox::invoke $bbox 2"
        pack $bbox -side right -fill x -padx 2m -pady 2m
    } else {
        ButtonBox $mw.bottom.buttons -spacing 0 -padx 10
        $mw.bottom.buttons add -text [::msgcat::mc "Close"] -command [list destroy $mw]
        bind $mw <Return> "ButtonBox::invoke $mw.bottom.buttons 0"
        bind $mw <Escape> "ButtonBox::invoke $mw.bottom.buttons 0"
    }
    pack $mw.bottom.buttons -side right -fill x -padx 2m -pady 2m

    set sep [Separator::create $mw.sep -orient horizontal]
    pack $sep -pady 1m -fill x -side bottom

    frame $mw.frame
    pack $mw.frame -side top -fill both -expand yes -padx 2m -pady 2m

    label $mw.thread -text $thread

    if {$replyP} {
        set title [::msgcat::mc "Message from:"]
    } else {
        set title [::msgcat::mc "Extras from:"]
    }

    frame $mw.title
    pack $mw.title -side top -anchor w -fill x -expand yes -in $mw.frame
    grid columnconfigure $mw.title 1 -weight 1

    if {[llength [jlib::connections]] > 1} {
	label $mw.title.lconnection -text [::msgcat::mc "Received by:"]
	label $mw.title.connection -text " [jlib::connection_jid $connid]" \
	    -font $font
	grid $mw.title.lconnection -row 0 -column 0 -sticky e
	grid $mw.title.connection  -row 0 -column 1 -sticky w
    }

    label $mw.title.lab -text $title
    menubutton $mw.title.mb -text $from -font $font -menu $mw.title.mb.menu
    subject_menu $mw.title.mb.menu $connid $from message
    grid $mw.title.lab -row 1 -column 0 -sticky e
    grid $mw.title.mb  -row 1 -column 1 -sticky w

    foreach tag [bind Menubutton] {
        if {[string first 1 $tag] >= 0} {
            regsub -all 1 $tag 3 new
            bind $mw.title.mb $new [bind Menubutton $tag]
        }
    }

    frame $mw.tspace
    pack $mw.tspace -side top -fill x -pady 0.5m -in $mw.frame

    frame $mw.rf
    grid columnconfigure $mw.rf 1 -weight 1

    set row 0

    if {$replyP || (![cequal $subject ""])} {
        label $mw.rf.lsubj -text [::msgcat::mc "Subject:"]
        entry $mw.rf.subj
        $mw.rf.subj insert 0 $subject
        if {[info tclversion] >= 8.4} {
            set bgcolor [lindex [$mw.rf.subj configure -background] 4]
            $mw.rf.subj configure -state readonly -readonlybackground $bgcolor
        } else {
            $mw.rf.subj configure -state disabled
        }
        grid $mw.rf.lsubj -row 0 -column 0 -sticky e
        grid $mw.rf.subj  -row 0 -column 1 -sticky ew
        incr row
    }

    pack $mw.rf -side top -anchor w -fill x -in $mw.frame

    frame $mw.rspace
    pack $mw.rspace -side top -fill x -in $mw.frame -pady 0.5m

    incr row
    set last $row
    hook::run message_process_x_hook row body \
	      $mw.rf $x $connid $from $type $replyP

    if {(!$replyP) && ($row == $last)} {
        destroy $mw
        return
    }
    # Ignore messages with empty body and no (or unsupported, e.g. jabber:x:event) extras
    if {[cequal $body ""] && ($row == $last)} {
        destroy $mw
        return
    }

    ScrolledWindow $mw.rsw
    text $mw.rbody -width 60 -height 8 -wrap word
    ::richtext::config $mw.rbody -using {url emoticon stylecode}
    ::richtext::render_message $mw.rbody $body ""
    $mw.rbody configure -state disabled
    pack $mw.rsw -side top -fill both -expand yes -in $mw.frame
    pack $mw.rbody -side top -fill both -expand yes -in $mw.rsw
    $mw.rsw setwidget $mw.rbody
 
    if {$replyP} {
        button $mw.cite -text [::msgcat::mc "Quote"] -command [list message::quote $mw $body]
        pack $mw.cite -side top -anchor e -in $mw.frame

        frame $mw.f
        grid columnconfigure $mw.f 1 -weight 1

        #label $mw.f.lto -text To:
        Entry $mw.f.to -dropenabled 1 -droptypes {JID {}} \
                -dropcmd [list message::jiddropcmd]
        $mw.f.to insert 0 $from

        label $mw.f.lsubj -text [::msgcat::mc "Reply subject:"]
        entry $mw.f.subj
        regsub {(^Re: )*} $subject {Re: } subject
        $mw.f.subj insert 0 $subject

        #grid $mw.f.lto   -row 0 -column 0 -sticky e
        #grid $mw.f.to    -row 0 -column 1 -sticky ew
        grid $mw.f.lsubj -row 1 -column 0 -sticky e
        grid $mw.f.subj  -row 1 -column 1 -sticky ew

        pack $mw.f -side top -anchor w -fill x -in $mw.frame

        frame $mw.space
        pack $mw.f -side top -anchor w -fill x -in $mw.frame -pady 1m

        ScrolledWindow $mw.sw
        pack $mw.sw -in $mw.frame -side top -fill both -expand yes

        textUndoable $mw.body -width 60 -height 8 -wrap word -font $font
        pack $mw.body -side top -fill both -expand yes -in $mw.sw
        bind $mw.body <Control-Return> "ButtonBox::invoke $bbox 0
                break"
        $mw.sw setwidget $mw.body

        focus $mw.body

	hook::run open_message_post_hook $mw $connid $from
    }

    BWidget::place $mw 0 0 center
    wm deiconify $mw
}

proc message::quote {mw body} {
    regsub -all {(^|\n)} $body {\1> } body
    $mw.body insert 0.0 $body
    $mw.body insert insert "\n"
}

proc message::process_x {rowvar bodyvar f x connid from type replyP} {
    upvar 2 $rowvar row
    upvar 2 $bodyvar body

    foreach xa $x {
	jlib::wrapper:splitxml $xa tag vars isempty chdata children

	set xmlns [jlib::wrapper:getattr $vars xmlns]
	switch -- $xmlns \
	    jabber:x:oob {
		set row [process_x_oob $f $children $row $from]
	    } \
	    $::NS(data) {
		if {![lempty $children]} {
		    process_x_data $f $connid $from $xa
		}
	    } \
	}

    return
}

hook::add message_process_x_hook message::process_x 99

proc message::process_x_oob {f x row from} {
    set desc ""
    set url ""
    foreach item $x {
        jlib::wrapper:splitxml $item tag vars isempty chdata children   

        switch -- $tag {
            desc -
	    url {
                set $tag $chdata
            }
        }
    }
    if {[cequal $url ""]} {
        return $row
    }
    if {[cequal $desc ""]} {
	set desc $url
    }

    label $f.luser$row -text [::msgcat::mc "Attached URL:"]
    set cb [button $f.user$row \
		   -text $desc \
		   -command [list browseurl $url]]
    balloon::setup $cb -text $url
    grid $f.luser$row -row $row -column 0 -sticky e
    grid $f.user$row  -row $row -column 1 -sticky ew

    incr row

    return $row
}

proc message::process_x_data {f connid from x} {
    data::draw_window [list $x] [list message::send_x_data $connid $from]
}

proc message::send_x_data {connid to w restags} {
    #set f $w.fields
    #set restags [data::get_tags $f]
    jlib::send_msg $to -xlist $restags -connection $connid
    destroy $w
}

proc message::send_dialog_item {m connid jid} {
    $m add command -label [::msgcat::mc "Send message..."] \
	-command [list message::send_dialog \
		       -to $jid -connection $connid]
}

hook::add roster_jid_popup_menu_hook message::send_dialog_item 15
hook::add message_dialog_menu_hook message::send_dialog_item 15
hook::add search_popup_menu_hook message::send_dialog_item 15
hook::add roster_create_groupchat_user_menu_hook message::send_dialog_item 15

package require sha1

proc message::generate_thread {from to} {
    return [sha1::sha1 $from$to[rand 1000000000]]
}

proc message::send_dialog {args} {
    global font
    variable msgid
    variable message_dest_list
    variable send_dialog_connid

    if {[lempty [jlib::connections]]} return

    set to ""
    set subject ""
    set group 0
    set cstate normal
    foreach {opt val} $args {
	switch -- $opt {
	    -to { set to $val }
	    -subject { set subject $val }
	    -thread { set thread $val }
	    -group { set group $val }
	    -connection {
		set connid $val
		set cstate disabled
	    }
	}
    }

    if {![info exists connid]} {
	if {$group} {
	    set connid [jlib::route ""]
	} else {
	    set connid [jlib::route $to]
	}
    }

    set mw .msgsend[incr msgid]
    toplevel $mw -class Message
    wm group $mw .

    set send_dialog_connid($mw) [jlib::connection_jid $connid]

    if {![info exists thread]} {
	set thread [generate_thread $send_dialog_connid($mw) $to]
    }

    if {$group} {
	if {$to != ""} {
	    set title [format [::msgcat::mc "Send message to group %s"] $to]
	} else {
	    set title [::msgcat::mc "Send message to group"]
	}
    } else {
	if {$to != ""} {
	    set title [format [::msgcat::mc "Send message to %s"] $to]
	} else {
	    set title [::msgcat::mc "Send message"]
	}
    }
    wm title $mw $title
    wm iconname $mw $title

    wm withdraw $mw

    #frame $mw.subj
    #label $mw.subj.lab -text Subject:
    #entry $mw.subj.entry
    #$mw.subj.entry insert 0 $subject
    #pack $mw.subj.lab $mw.subj.entry -side left
    #pack $mw.subj -side top -anchor w

    frame $mw.bottom
    pack $mw.bottom -side bottom -fill x

    set bbox [ButtonBox $mw.bottom.buttons -spacing 10 -padx 10]
    $bbox add -text [::msgcat::mc "Send"] \
	-command [list message::send $mw -group $group -connection $connid]
    $bbox add -text [::msgcat::mc "Cancel"] -command [list destroy $mw]
    bind $mw <Control-Return> "ButtonBox::invoke $bbox 0"
    bind $mw <Escape> "ButtonBox::invoke $bbox 1"
    pack $bbox -side right -fill x -padx 2m -pady 2m

    set sep [Separator::create $mw.sep -orient horizontal]
    pack $sep -pady 1m -fill x -side bottom

    label $mw.thread -text $thread

    frame $mw.frame
    pack $mw.frame -side top -fill both -expand yes -padx 2m -pady 2m

    frame $mw.f
    grid columnconfigure $mw.f 1 -weight 1

    set connections {}
    if {[llength [jlib::connections]] > 1} {
	foreach c [jlib::connections] {
	    lappend connections [jlib::connection_jid $c]
	}
	label $mw.f.lconnection -text [::msgcat::mc "From: "]
	ComboBox $mw.f.connection \
	    -textvariable [namespace current]::send_dialog_connid($mw) \
	    -values $connections \
	    -font $font \
	    -state $cstate

	grid $mw.f.lconnection -row 0 -column 0 -sticky e
	grid $mw.f.connection  -row 0 -column 1 -sticky ew
    }

    if {$group} {
	# TODO reflect changes in connid
	label $mw.f.lto -text [::msgcat::mc "Group: "]
	ComboBox $mw.f.to -text $to \
	    -values [roster::get_groups $connid \
			 -nested $::ifacetk::roster::options(nested) \
			 -delimiter $::ifacetk::roster::options(nested_delimiter) \
			 -undefined 1]
    } else {
	label $mw.f.lto -text [::msgcat::mc "To: "]
	ComboBox $mw.f.to -text $to \
	    -dropenabled 1 -droptypes {JID {}} \
	    -dropcmd [list message::jiddropcmd] \
	    -values $message_dest_list
    }
    
    label $mw.f.lsubj -text [::msgcat::mc "Subject: "]
    entry $mw.f.subj
    $mw.f.subj insert 0 $subject

    grid $mw.f.lto   -row 1 -column 0 -sticky e
    grid $mw.f.to    -row 1 -column 1 -sticky ew
    grid $mw.f.lsubj -row 2 -column 0 -sticky e
    grid $mw.f.subj  -row 2 -column 1 -sticky ew

    pack $mw.f -side top -anchor w -fill x -in $mw.frame

    frame $mw.space
    pack $mw.f -side top -anchor w -fill x -in $mw.frame -pady 1m

    ScrolledWindow $mw.sw
    pack $mw.sw -in $mw.frame -side top -fill both -expand yes

    textUndoable $mw.body -width 60 -height 8 -wrap word -font $font
    pack $mw.body -side top -fill both -expand yes -in $mw.sw
    bind $mw.body <Control-Return> "ButtonBox::invoke $bbox 0
            break"
    $mw.sw setwidget $mw.body

    if {$to != ""} {
        focus $mw.f.subj
    } else {
        focus $mw.f.to
    }

    hook::run open_message_post_hook $mw $connid $to

    BWidget::place $mw 0 0 center
    wm deiconify $mw
}

proc message::send0 {mw args} {
    variable send_dialog_connid
    
    foreach c [jlib::connections] {
	if {[jlib::connection_jid $c] == $send_dialog_connid($mw)} {
	    set connid $c
	}
    }
    unset send_dialog_connid($mw)

    if {![info exists connid]} {
	eval [list send $mw] $args
    } else {
	eval [list send $mw -connection $connid] $args
    }
}

proc message::send {mw args} {
    variable message_dest_list

    set group 0
    foreach {opt val} $args {
	switch -- $opt {
	    -group { set group $val }
	    -connection { set connid $val }
	}
    }

    set jid [$mw.f.to cget -text]
    
    if {$group} {
	set jids [roster::get_group_jids $connid $jid \
		      -nested $::ifacetk::roster::options(nested) \
		      -delimiter $::ifacetk::roster::options(nested_delimiter)]
    } else {
	set message_dest_list [update_combo_list $message_dest_list $jid 20]
	set jids [list $jid]
	if {![info exists connid]} {
	    set connid [jlib::route $jid]
	}
    }

    set thread [$mw.thread cget -text]
    set subj [$mw.f.subj get]
    set body [$mw.body get 1.0 {end -1 chars}]

    foreach jid $jids {
	if {!$group || [::roster::itemconfig $connid $jid -isuser]} {
	    send_msg $jid -type normal \
		-subject $subj -body $body -thread $thread \
		-connection $connid
	}
    }

    destroy $mw
}

proc message::send_msg {to args} {
    array set params [list -xlist {}]
    array set params $args

    set command [list jlib::send_msg $to]
    set xs $params(-xlist)
    unset params(-xlist)

    if {![info exists params(-connection)]} {
	set params(-connection) [jlib::route $to]
    }

    if {[info exists params(-body)]} {
        set log_body $params(-body)
        foreach tag [list signed encrypted] {
            if {[cequal [info commands ::ssj::${tag}:output] ""]} {
                continue
            }

            if {[catch { ssj::${tag}:output $params(-connection) $params(-body) $to } chdata]} {
                debugmsg message "ssj::${tag}:output: $chdata"
                return [list error ssj]
            }
            
            if {![cequal $chdata ""]} {
                lappend xs [jlib::wrapper:createtag x \
                                -vars "xmlns jabber:x:$tag" -chdata $chdata]
                if {[cequal $tag encrypted]} {
                    set params(-body) [::msgcat::mc "This message is encrypted."]
                }
            }
        }
    } else {
        set log_body ""
    }
    if {[info exists params(-subject)]} {
        set log_subject $params(-subject)
    } else {
        set log_subject ""
    }
    if {[llength $xs] > 0} {
        lappend command -xlist $xs
    }

    foreach {k v} [array get params] {
        lappend command $k $v
    }

    eval $command

#    if {(![info exists params(-type)]) || ($params(-type) == "normal") } {
#        ::message_archive::log_message \
#	    [jlib::connection_jid $params(-connection)] \
#            $to $log_subject $log_body $xs
#    }

    return [list success $xs]
}

proc message::jiddropcmd {target source pos op type data} {
    set jid [lindex $data 1]
    $target delete 0 end
    $target insert 0 $jid
}

###############################################################################

proc message::show_subscribe_dialog {connid from type x args} {
    variable msgid
    global font

    if {$type != "subscribe"} return

    set status ""

    foreach {opt val} $args {
        switch -- $opt {
            -status { set status $val }
            default {
		debugmsg message \
			 "SHOW_SUBSCRIBE_MESSAGE: unknown option $opt $val"
	    }
        }
    }

    set mw .subscshow[incr msgid]
    toplevel $mw -class Message
    wm group $mw .
    wm withdraw $mw

    set title [format [::msgcat::mc "Subscription request from %s"] $from]
    wm title $mw $title
    wm iconname $mw $title

    set bbox [ButtonBox $mw.buttons -spacing 0 -padx 10 -default 0]
    $bbox add -text [::msgcat::mc "Approve subscription"] \
	      -command [list [namespace current]::subscribe $mw $connid $from]
    $bbox add -text [::msgcat::mc "Decline subscription"] \
	      -command [list [namespace current]::unsubscribe $mw $connid $from]
    bind $mw <Return> "ButtonBox::invoke $bbox default"
    bind $mw <Escape> "ButtonBox::invoke $bbox 1"
    pack $bbox -side bottom -anchor e -padx 2m -pady 2m

    set sep [Separator::create $mw.sep -orient horizontal]
    pack $sep -pady 1m -fill x -side bottom

    frame $mw.frame
    pack $mw.frame -side top -fill both -expand yes -padx 2m -pady 2m

    frame $mw.subj
    pack $mw.subj -side top -anchor w -fill x -expand yes -in $mw.frame
    grid columnconfigure $mw.subj 1 -weight 1

    if {[llength [jlib::connections]] > 1} {
	label $mw.subj.lconnection -text [::msgcat::mc "Received by:"]
	label $mw.subj.connection -text " [jlib::connection_jid $connid]" \
	    -font $font
	grid $mw.subj.lconnection -row 0 -column 0 -sticky e
	grid $mw.subj.connection  -row 0 -column 1 -sticky w
    }


    label $mw.subj.lab -text [::msgcat::mc "Subscription request from:"]
    menubutton $mw.subj.mb -text $from -font $font -menu $mw.subj.mb.menu
    subject_menu $mw.subj.mb.menu $connid $from subscribe
    grid $mw.subj.lab -row 1 -column 0 -sticky e
    grid $mw.subj.mb  -row 1 -column 1 -sticky w

    foreach tag [bind Menubutton] {
        if {[string first 1 $tag] >= 0} {
            regsub -all 1 $tag 3 new
            bind $mw.subj.mb $new [bind Menubutton $tag]
        }
    }

    frame $mw.space
    pack $mw.space -side top -fill x -pady 0.5m -in $mw.frame

    ScrolledWindow $mw.sw
    pack $mw.sw -side top -fill both -expand yes -in $mw.frame

    text $mw.body -width 60 -height 8 -wrap word
    $mw.body insert 0.0 $status
    $mw.body configure -state disabled
    pack $mw.body -side bottom -fill both -expand yes -in $mw.sw
    $mw.sw setwidget $mw.body

    BWidget::place $mw 0 0 center
    wm deiconify $mw
}

hook::add client_presence_hook message::show_subscribe_dialog

###############################################################################

proc message::show_unsubscribed_dialog {connid from type x args} {
    variable msgid

    if {$type != "unsubscribed"} return

    MessageDlg .unsubscribed[incr msgid] -aspect 50000 -icon info \
	-title [::msgcat::mc "Unsubscribed from %s" $from] \
	-message [::msgcat::mc "You are unsubscribed from %s" $from] \
	-type user -buttons {ok} -default 0 -cancel 0
}

hook::add client_presence_hook message::show_unsubscribed_dialog

###############################################################################

proc message::subscribe {mw connid jid} {
    jlib::send_presence -to $jid -type subscribed -connection $connid

    switch -- [roster::itemconfig $connid \
				  [tolower_node_and_domain $jid] -subsc] {
        {}   -
        none -
        from {
            message::send_subscribe_dialog $jid -connection $connid
        }
    }

    destroy $mw
}

###############################################################################

proc message::unsubscribe {mw connid jid} {
    ::roster::remove_item $connid [tolower_node_and_domain $jid]
    destroy $mw
}

###############################################################################

proc message::destroy_subscription_dialogs {connid jid name groups subsc ask} {
    switch -- $subsc {
	both -
	from {}
	default { return }
    }

    foreach mw [winfo children .] {
	if {![string match .subscshow* $mw]} continue

	set curjid [$mw.subj.mb cget -text]
	if {$curjid == $jid} {
	    destroy $mw
	}
    }
}

hook::add roster_push_hook message::destroy_subscription_dialogs

###############################################################################

proc message::disco_popup_menu {m bw tnode data parentdata} {
    lassign $data type connid jid node
    switch -- $type {
	item {
	    set identities [disco::get_jid_identities $connid $jid $node]

	    foreach id $identities {
		if {[jlib::wrapper:getattr $id category] == "client"} {
		    subject_menu $m $connid $jid message
		    break
		}
	    }
	}
    }

}

hook::add disco_node_menu_hook message::disco_popup_menu

###############################################################################

proc message::subject_menu {m connid jid type} {
    if {[winfo exists $m]} {
        destroy $m          
    }                       
    menu $m -tearoff 0

    hook::run message_dialog_menu_hook $m $connid $jid

    return $m
}   

###############################################################################

proc message::add_separator {m connid jid} {
    $m add separator
}

hook::add message_dialog_menu_hook \
    [namespace current]::message::add_separator 40
hook::add message_dialog_menu_hook \
    [namespace current]::message::add_separator 50

###############################################################################

proc message::add_subscribe_menu_item {m connid jid} {
    set chatid [chat::chatid $connid [node_and_server_from_jid $jid]]
    if {[chat::is_groupchat $chatid]} {
	set real_jid [muc::get_real_jid $connid $jid]
	if {$real_jid != ""} {
	    set jid $real_jid
	    set state normal
	} else {
	    set state disabled
	}
    } else {
	set state normal
    }
    set user [node_and_server_from_jid $jid]
    if {[roster::itemconfig $connid $user -subsc] != ""} {
	set state disabled
    }
    $m add command -label [::msgcat::mc "Add user to roster..."] \
		   -state $state \
		   -command [list message::send_subscribe_dialog $user \
				  -connection $connid]
}

hook::add chat_create_user_menu_hook \
    [namespace current]::message::add_subscribe_menu_item 35
hook::add message_dialog_menu_hook \
    [namespace current]::message::add_subscribe_menu_item 35
hook::add search_popup_menu_hook \
    [namespace current]::message::add_subscribe_menu_item 35

###############################################################################

proc message::send_subscribe_dialog {to args} {
    global font
    variable msgid
    variable send_subscribe_connid

    if {[lempty [jlib::connections]]} return

    set cstate normal

    foreach {opt val} $args {
	switch -- $opt {
	    -connection {
		set connid $val
		set cstate disabled
	    }
	}
    }
    if {![info exists connid]} {
	set connid [jlib::route $to]
    }
    set send_subscribe_connid [jlib::connection_jid $connid]

    set mw .subscsend[incr msgid]
    toplevel $mw -class Message
    wm group $mw .
    wm withdraw $mw

    if {[cequal $to ""]} {
        set title [::msgcat::mc "Send subscription request"]
    } else {
        set title [format [::msgcat::mc "Send subscription request to %s"] $to]
    }
    wm title $mw $title
    wm iconname $mw $title

    set bbox [ButtonBox $mw.buttons -spacing 0 -padx 10 -default 0]
    $bbox add -text [::msgcat::mc "Request subscription"] \
        -command [list message::send_subscribe0 $mw]
    $bbox add -text [::msgcat::mc "Cancel"] -command [list destroy $mw]
    bind $mw <Return> "ButtonBox::invoke $bbox default"
    bind $mw <Escape> "ButtonBox::invoke $bbox 1"
    pack $bbox -side bottom -anchor e -padx 2m -pady 2m

    set sep [Separator::create $mw.sep -orient horizontal]
    pack $sep -pady 1m -fill x -side bottom

    frame $mw.frame
    pack $mw.frame -side top -fill both -expand yes -padx 2m -pady 2m

    frame $mw.subj
    pack $mw.subj -side top -anchor w -fill x -expand yes -in $mw.frame
    grid columnconfigure $mw.subj 1 -weight 1

    set connections {}
    if {[llength [jlib::connections]] > 1} {
	foreach c [jlib::connections] {
	    lappend connections [jlib::connection_jid $c]
	}
	label $mw.subj.lconnection -text [::msgcat::mc "From: "]
	ComboBox $mw.subj.connection \
	    -textvariable [namespace current]::send_subscribe_connid \
	    -values $connections \
	    -font $font \
	    -state $cstate

	grid $mw.subj.lconnection -row 0 -column 0 -sticky e
	grid $mw.subj.connection  -row 0 -column 1 -sticky ew
    }

    label $mw.subj.lab -text [::msgcat::mc "Send request to: "]
    entry $mw.subj.entry -font $font
    $mw.subj.entry insert 0 $to
    grid $mw.subj.lab   -row 1 -column 0 -sticky e
    grid $mw.subj.entry -row 1 -column 1 -sticky ew

    frame $mw.space
    pack $mw.space -side top -fill x -in $mw.frame -pady 0.5m

    ScrolledWindow $mw.sw
    pack $mw.sw -side top -fill both -expand yes -in $mw.frame

    textUndoable $mw.body -width 60 -height 8 -wrap word
    $mw.body insert 0.0 [::msgcat::mc "I would like to add you to my roster."]
    pack $mw.body -side top -fill both -expand yes -in $mw.sw
    $mw.sw setwidget $mw.body

    focus $mw.subj.entry

    BWidget::place $mw 0 0 center
    wm deiconify $mw
}

###############################################################################

proc message::send_subscribe0 {mw} {
    variable send_subscribe_connid

    foreach c [jlib::connections] {
	if {[jlib::connection_jid $c] == $send_subscribe_connid} {
	    set connid $c
	}
    }
    if {![info exists connid]} {
	send_subscribe $mw
    } else {
	send_subscribe $mw -connection $connid
    }
}

###############################################################################

proc message::send_subscribe {mw args} {
    set jid [$mw.subj.entry get]
    
    foreach {opt val} $args {
	switch -- $opt {
	    -connection { set connid $val }
	}
    }
    if {![info exists connid]} {
	set connid [jlib::route $jid]
    }

    jlib::send_presence -to $jid -type subscribe \
        -stat [$mw.body get 1.0 end] \
	-connection $connid

    jlib::send_iq set \
        [jlib::wrapper:createtag query \
             -vars {xmlns jabber:iq:roster} \
             -subtags [list [jlib::wrapper:createtag item \
                                 -vars [list jid $jid]]]] \
        -command "itemedit::show_dialog \
                      [list $connid [tolower_node_and_domain $jid]] ;#" \
	-connection $connid

    destroy $mw

}

###############################################################################

proc message::resubscribe_menu_item {m connid jid} {
    set rjid [roster::find_jid $connid $jid]
    if {$rjid == ""} {
	set state disabled
    } else {
	set state normal
    }
    set mm [menu $m.subscription -tearoff 0]
    $mm add command -label [::msgcat::mc "Request subscription"] \
	-command [list jlib::send_presence \
		      -to $rjid \
		      -type subscribe \
		      -connection $connid]
    $mm add command -label [::msgcat::mc "Grant subscription"] \
	-command [list jlib::send_presence \
		      -to $rjid \
		      -type subscribed \
		      -connection $connid]

    $mm add command -label [::msgcat::mc "Remove subscription"] \
	-command [list jlib::send_presence \
		      -to $rjid \
		      -connection $connid \
		      -type unsubscribed]
	
    $mm add command -label [::msgcat::mc "Unsubscribe"] \
	-command [list jlib::send_presence \
		      -to $rjid \
		      -connection $connid \
		      -type unsubscribe]
	

    $m add cascad -label [::msgcat::mc "Subscription"] \
		  -menu $mm \
		  -state $state
}

hook::add roster_jid_popup_menu_hook message::resubscribe_menu_item 30
hook::add roster_service_popup_menu_hook message::resubscribe_menu_item 30

###############################################################################

# vim:ts=8:sw=4:sts=4:noet
